﻿using System.Collections.Generic;
using System.Linq;
using CoreEx.Database.Client;
using CoreEx.Database.Metadata;
using CoreEx.Database.Metadata.Generation;
using CoreEx.Database.MetaData.Generation;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using LinFu.IoC;
using IModelGenerator = CoreEx.Database.Metadata.Generation.IModelGenerator;
using ITypeGenerator = CoreEx.Database.Metadata.Generation.ITypeGenerator;
using System.CodeDom;
namespace CoreEx.Database.MetaData.Implementation.Generation
{
    [Implements(typeof(IModelGenerator), ServiceName = "C#")]
    [Implements(typeof(IModelGenerator), ServiceName = "VB")]
    public class ModelGenerator : IModelGenerator, IInitialize
    {
        private IServiceContainer _serviceContainer;
        private ModelGenerationOptions _modelGenerationOptions;

        ///// <summary>
        ///// Gets or sets the <see cref="IModelWriter"/> instance that is responsible for writing 
        ///// the generated model to disc.
        ///// </summary>
        //public IModelWriter ModelWriter { get; set; }

        /// <summary>
        /// Gets or sets the <see cref="ITypeGenerator"/> instance that is responsible for 
        /// generating entity class definition. 
        /// </summary>
        public ITypeGenerator TypeGenerator { get; set; }


        /// <summary>
        /// Gets or sets the <see cref="ILinkTableInspector"/> instance that is responsible 
        /// for determinig if a given <see cref="TableInfo"/> represents a link table.
        /// </summary>
        public ILinkTableInspector LinkTableInspector { get; set; }

        /// <summary>
        /// Generates model/entity types based on database metadata. 
        /// </summary>
        /// <param name="modelGenerationOptions">The <see cref="ModelGenerationOptions"/> instance that describes the generation options.</param>        
        public void Generate(ModelGenerationOptions modelGenerationOptions)
        {
            _modelGenerationOptions = modelGenerationOptions;
            ConfigureDatabaseConnection();
            var generatedTypes = GenerateTypes();
            WriteGeneratedTypesToDisc(generatedTypes);
        }

        private IEnumerable<TableInfo> GetTables()
        {
            const bool useCachedRepository = false;
            var metadataRepository = _serviceContainer.GetService<IMetadataRepository>(
                _modelGenerationOptions.Namespace, useCachedRepository);                
            return metadataRepository.Tables;
        }


        private IEnumerable<CodeTypeDeclaration> GenerateTypes()
        {
            var tables = GetTables();
            var generatesTypes =
                tables.Select(tableInfo => TypeGenerator.Generate(
                    tableInfo)).ToList();
            return generatesTypes;                            
        }


        private void WriteGeneratedTypesToDisc(IEnumerable<CodeTypeDeclaration> generatedTypes)
        {
           // ModelWriter.WriteModel(generatedTypes,_modelGenerationOptions.OutputDirectory);
        }


        private void ConfigureDatabaseConnection()
        {
            var dbConnectionInfoProvider = _serviceContainer.GetService<IDbConnectionInfoProvider>();
            dbConnectionInfoProvider.AddConnection(_modelGenerationOptions.Namespace, _modelGenerationOptions.ProviderName,
                                                   _modelGenerationOptions.ConnectionString);
        }

        /// <summary>
        /// Initializes this service instance
        /// </summary>        
        public void Initialize(IServiceContainer source)
        {
            _serviceContainer = source;
            
        }
    }
}
